package naga.x.platform2.channel.weixin;

import java.text.MessageFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import naga.x.platform2.app.AppController;
import naga.x.platform2.app.AppErrorController;
import naga.x.platform2.app.Channel;
import naga.x.platform2.app.model.Recharge;
import naga.x.platform2.app.support.RechargeSupport;
import naga.x.platform2.channel.weixin.support.AccessTokenResponse;
import naga.x.platform2.channel.weixin.support.GetOrderResponse;
import naga.x.platform2.channel.weixin.support.OrderRequest;
import naga.x.platform2.channel.weixin.support.PayResult;
import naga.x.platform2.channel.weixin.support.UserInfoResponse;
import naga.x.platform2.channel.weixin.support.WeiXinApi;
import naga.x.platform2.channel.weixin.support.WeiXinConfig;
import naga.x.platform2.channel.weixin.support.WeiXinOrderRequest;
import naga.x.platform2.support.RequestPath;
import naga.x.platform2.utils.CommonUtils;
import naga.x.platform2.utils.HttpUtils;
import naga.x.platform2.utils.IOUtils;
import naga.x.platform2.utils.NumberUtils;
import naga.x.platform2.utils.StringUtils;

/**
 * 微信
 * @see <a href="http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html">网页授权获取用户基本信息</a>
 * @see <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1">公众号支付</a>
 * @author yang.li
 *
 */
@Controller
public class WeiXinController {

	@Autowired
	private WeiXinConfig config;
	@Autowired
	private RechargeSupport support;
	
	private static Channel channel = Channel.WEIXIN;
	
	private static final Logger LOG = LoggerFactory.getLogger(WeiXinController.class);
	
	/**
	 * 请求微信登录
	 * @return
	 */
	@RequestMapping(path = RequestPath.WX_LOGIN)
	public String login() {
//        //'https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type={2}&scope={3}&state={4}#wechat_redirect';
		String redirectUrl = MessageFormat.format(WeiXinApi.URL_AUTH,
				config.getAppId(),
				CommonUtils.encodeURL(WeiXinApi.URL_LOGIN_REDIRECT, IOUtils.UTF8),
				"code",
				"snsapi_userinfo",
				"0");
		return UrlBasedViewResolver.REDIRECT_URL_PREFIX + redirectUrl;
	}
	
	/**
	 * 微信登录回调，由微信调用
	 * @param code
	 */
	@RequestMapping(path = RequestPath.WX_LOGIN_CALLBACK)
	public String loginCallback(String code) {
		//https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code
		String url = MessageFormat.format(WeiXinApi.URL_ACCESS_TOKEN, config.getAppId(), config.getAppSec(), code);
		AccessTokenResponse res = null;
		try {
			String json = HttpUtils.post(url);
			res = JSON.parseObject(json, AccessTokenResponse.class);
			if (res == null || res.getErrcode() != 0) { // 出错
				return UrlBasedViewResolver.REDIRECT_URL_PREFIX + AppErrorController.PATH;
			}
		} catch (Exception e) {
			LOG.error("[WEIXIIN LOGIN CALLBACK ERROR]CODE[" + code + "]CAUSE[ACCESS TOKEN]", e);
			return UrlBasedViewResolver.REDIRECT_URL_PREFIX + AppErrorController.PATH;
		}
//	        //https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN
		url = MessageFormat.format(WeiXinApi.URL_USER_INFO, res.getAccess_token(), res.getOpenid());
		UserInfoResponse res2 = null;
		try {
			String json = HttpUtils.post(url);
			res2 = JSON.parseObject(json, UserInfoResponse.class);
			if (res2 == null || res2.getErrcode() != 0) { // 出错
				return UrlBasedViewResolver.REDIRECT_URL_PREFIX + AppErrorController.PATH;
			}
		} catch (Exception e) {
			LOG.error("[WEIXIN LOGIN CALLBACK ERROR]CODE[" + code + "]TOKEN[" + res.getAccess_token() + "]OPENID[" + res.getOpenid() + "]CAUSE[USERINFO]", e);
			return UrlBasedViewResolver.REDIRECT_URL_PREFIX + AppErrorController.PATH;
		}
//		http://city.arkfel.com?openid={0}&nickname={1}&sex={2,number,#}&province={3}&city={4}&headimgurl={5}
		url = MessageFormat.format(WeiXinApi.URL_GAME,
				res2.getOpenid(),
				res2.getNickname(),
				res2.getSex(),
				res2.getProvince(),
				res2.getCity(),
				res2.getHeadimgurl());
		return UrlBasedViewResolver.REDIRECT_URL_PREFIX + url;
	}
	
	@RequestMapping(path = RequestPath.WX_PAY, method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
	@ResponseBody
	public Object pay(OrderRequest req) {
		if (req == null) {
			return null;
		}
		WeiXinOrderRequest wxreq = new WeiXinOrderRequest(req);
		String xml = HttpUtils.post(WeiXinApi.URL_GET_ORDER, wxreq.toXmlBytes());
		GetOrderResponse res = GetOrderResponse.parse(xml);
		LOG.info("[WEIXIN GET ORDER]" + xml);
		return res;
	}
	
	@RequestMapping(path = RequestPath.WX_PAY_CALLBACK, method = RequestMethod.POST, produces = "application/xml; charset=UTF-8")
	@ResponseBody
	public String payCallback(@RequestBody byte[] req) {
		PayResult result = PayResult.parse(req);
		LOG.info("[WEIXIN PAY]" + (result != null ? result.refToString() : null));
		String returnCode = WeiXinApi.RESPONSE_FAIL, returnMsg = "未知错误";
		if (result != null && result.isSuccess()) {
			if (result.verify()) {
				String attach = result.getAttach(); // serverId:productId:playerId
				String[] strs = StringUtils.split(attach, ":");
				if (strs != null && strs.length == 3) {
					int serverId = NumberUtils.parseInt(strs[0]);
					int productId = NumberUtils.parseInt(strs[1]);
					long playerId = NumberUtils.parseLong(strs[2]);
					Recharge r = new Recharge(channel.name + ":" + result.getTransaction_id(), playerId, serverId, result.getTotal_fee() / 100, -1, productId, channel.name);
					if (support.offer(r)) {
						returnCode = WeiXinApi.RESPONSE_SUCC;
					} else {
						returnMsg = "订单重复";
					}
				}
			} else {
				returnMsg = "签名错误";
			}
		}
		String xml = PayResult.response(returnCode, returnMsg);
		LOG.info("[WEIXIN PAY RESPONSE]" + xml);
		return xml;
	}
	
	@RequestMapping(path = RequestPath.WX_PAY_OLD_PLATFORM, method = RequestMethod.POST, produces = "application/json; charset=UTF-8")
	@ResponseBody
	public Object payCallbackForOldPlatform(String orderId, int serverId, long playerId, int productId, int money, String sign) {
		String s = WeiXinApi.makeSign("orderId", orderId, "serverId", serverId, "playerId", playerId, "productId", productId, "money", money);
		JSONObject result = new JSONObject(2);
		result.put("succ", 0);
		if (!s.equals(sign)) {
			result.put("error", "签名错误");
			LOG.info("[WEIXIN OLD PLATFORM PAY ERROR]ORDER[{}]SERVER[{}]PLAYER[{}]PRODUCT[{}]MONEY[{}]SIGN[{}]", orderId, serverId, playerId, productId, money, sign);
			return result;
		}
		Recharge recharge = new Recharge(channel.name + ":" + orderId, playerId, serverId, money, -1, productId, channel.name);
		boolean succ = support.offer(recharge);
		LOG.info("[WEIXIN OLD PLATFORM PAY]{}RESULT[{}]", recharge.toString(), succ ? "SUCC" : "DUPLICATE");
		if (succ) {
			result.put("succ", 1);
		} else {
			result.put("error", "订单重复");
		}
		return result;
	}
	
}
